use futures::stream::StreamExt;
use iflow_cli_sdk_rust::error::IFlowError;
use iflow_cli_sdk_rust::{IFlowClient, IFlowOptions, Message};
use std::io::Write;
use std::sync::{Arc, Mutex};

/// Parameters for communicating with iFlow CLI via ACP client
#[derive(Debug)]
pub struct AcpClientParams<'a> {
    pub prompt: &'a str,
    pub base_url: &'a str,
    pub model: &'a str,
    pub working_directory: &'a str,
    pub timeout: u32,
    pub debug: bool,
}

/// Communicate with iFlow CLI via ACP client
/// Returns Ok(Some(summary)) when a summary was generated, Ok(None) when nothing to summarize,
/// or Err(...) on error.
pub async fn communicate_with_iflow_cli_via_acp(
    params: AcpClientParams<'_>,
) -> Result<Option<String>, String> {
    let AcpClientParams {
        prompt,
        base_url,
        model,
        working_directory,
        timeout,
        debug,
    } = params;
    use crate::github::outputs::write_step_summary;
    use crate::github::summary::generate_summary_markdown;

    // Holder to pass the generated summary out of the LocalSet closure
    let summary_holder = Arc::new(Mutex::new(None::<String>));

    // Initialize logging with environment variable support
    let log_level = if debug || std::env::var("ACTIONS_STEP_DEBUG").is_ok() {
        tracing::Level::DEBUG
    } else {
        tracing::Level::INFO
    };

    tracing_subscriber::fmt().with_max_level(log_level).init();

    println!("🚀 Starting iFlow WebSocket client...");

    // Use LocalSet for spawn_local compatibility
    let local = tokio::task::LocalSet::new();
    let summary_holder_clone = summary_holder.clone();
    local
        .run_until(async move {
            // Configure client options with WebSocket configuration and custom timeout
            let custom_timeout_secs = timeout as f64;
            let mut process_config = iflow_cli_sdk_rust::types::ProcessConfig::new()
                .enable_auto_start()
                .start_port(8090);

            if debug {
                process_config = process_config.enable_debug();
            }

            let options = IFlowOptions::new()
                .with_websocket_config(iflow_cli_sdk_rust::types::WebSocketConfig::auto_start())
                .with_timeout(custom_timeout_secs)
                .with_process_config(process_config)
                .with_permission_mode(iflow_cli_sdk_rust::types::PermissionMode::Auto);

            // Create and connect client
            let mut client = IFlowClient::new(Some(options));

            println!("🔗 Connecting to iFlow via WebSocket...");
            client
                .connect()
                .await
                .map_err(|e| format!("Failed to connect: {}", e))?;
            println!("✅ Connected to iFlow via WebSocket");

            // Receive and process responses
            println!("📥 Receiving responses...");
            let mut message_stream = client.messages();

            // Store plan entries to track progress
            let mut plan_entries: Vec<(String, iflow_cli_sdk_rust::types::PlanStatus)> = Vec::new();

            let summary_holder_for_task = summary_holder_clone.clone();
            let message_task = tokio::task::spawn_local(async move {
                let mut stdout = std::io::stdout();
                let mut collected_messages = String::new();

                while let Some(message) = message_stream.next().await {
                    match message {
                        Message::Assistant { content } => {
                            print!("🤖 Assistant: {}", content);
                            if let Err(err) = stdout.flush() {
                                eprintln!("❌ Error flushing stdout: {}", err);
                                break;
                            }

                            // Collect assistant messages for summary
                            collected_messages.push_str(&format!("\n🤖 Assistant: {}", content));
                        }
                        Message::ToolCall { id, name, status } => {
                            println!("🔧 Tool call: {} ({}) {:?}", id, name, status);

                            // Collect tool call messages for summary
                            collected_messages
                                .push_str(&format!("🔧 Tool call: {} ({}) {:?}", id, name, status));
                        }
                        Message::Plan { entries } => {
                            // Update plan entries
                            plan_entries.clear();
                            for entry in entries {
                                plan_entries.push((entry.content, entry.status));
                            }

                            // Display all plan entries with status
                            if !plan_entries.is_empty() {
                                println!("📋 Plan:");
                                collected_messages.push_str("\n📋 Plan:");
                                for (i, (content, status)) in plan_entries.iter().enumerate() {
                                    let status_icon = match status {
                                        iflow_cli_sdk_rust::types::PlanStatus::Pending => "⏳",
                                        iflow_cli_sdk_rust::types::PlanStatus::InProgress => "🔄",
                                        iflow_cli_sdk_rust::types::PlanStatus::Completed => "✅",
                                    };
                                    println!("  {}. {} {}", i + 1, status_icon, content);
                                    collected_messages.push_str(&format!(
                                        "{}. {} {}",
                                        i + 1,
                                        status_icon,
                                        content
                                    ));
                                }
                            }
                        }
                        Message::TaskFinish { .. } => {
                            println!("✅ Task completed");
                            collected_messages.push_str("\n✅ Task completed");
                            break;
                        }
                        Message::Error {
                            code,
                            message: msg,
                            details: _,
                        } => {
                            eprintln!("❌ Error {}: {}", code, msg);
                            collected_messages.push_str(&format!("\n❌ Error {}: {}", code, msg));
                            break;
                        }
                        Message::User { content } => {
                            println!("👤 User message: {}", content);
                            collected_messages.push_str(&format!("\n👤 User message: {}", content));
                        }
                    }
                }

                collected_messages
            });

            // Send a prompt message
            // println!("📤 User prompt: {}", prompt);

            // Handle the send_message result to catch timeout errors
            match client.send_message(prompt, None).await {
                Ok(()) => {
                    println!("✅ Prompt message sent successfully");
                }
                Err(IFlowError::Timeout(msg)) => {
                    eprintln!("⏰ Timeout error occurred: {}", msg);
                    eprintln!("This may be due to processing delays.");
                    eprintln!("Consider increasing the timeout or checking the iFlow process.");
                }
                Err(e) => {
                    eprintln!("❌ Error sending message: {}", e);
                    return Err(format!("{}", e));
                }
            }

            // Wait for the message handling task to finish with a timeout
            let message_result = match tokio::time::timeout(
                std::time::Duration::from_secs_f64(custom_timeout_secs),
                message_task,
            )
            .await
            {
                Ok(Ok(collected_messages)) => {
                    println!("✅ Message handling completed successfully");

                    // Prepare configuration map for summary generation
                    let mut config_map = std::collections::HashMap::new();
                    config_map.insert("isTimeout", serde_json::Value::Bool(false));
                    config_map.insert(
                        "timeout",
                        serde_json::Value::Number(serde_json::Number::from(timeout)),
                    );
                    config_map.insert("model", serde_json::Value::String(model.to_string()));
                    config_map.insert("baseURL", serde_json::Value::String(base_url.to_string()));
                    config_map.insert(
                        "workingDir",
                        serde_json::Value::String(working_directory.to_string()),
                    );
                    config_map.insert("prompt", serde_json::Value::String(prompt.to_string()));

                    // Generate summary
                    let summary_content =
                        generate_summary_markdown(&collected_messages, 0, &config_map);

                    // Write collected messages to GitHub step summary if in GitHub Actions environment
                    if std::env::var("GITHUB_ACTIONS").is_ok()
                        && let Err(e) = write_step_summary(&summary_content)
                    {
                        eprintln!("⚠️  Warning: Failed to write step summary: {}", e);
                    }

                    // Store the generated summary into the shared holder so the outer
                    // function can access it after the LocalSet completes.
                    if let Ok(mut guard) = summary_holder_for_task.lock() {
                        *guard = Some(summary_content.clone());
                    }

                    Ok(())
                }
                Ok(Err(err)) => {
                    eprintln!("❌ Error in message handling: {}", err);
                    Err(format!("Error in message handling: {}", err))
                }
                Err(_) => {
                    println!("⏰ Timeout waiting for message handling to complete");
                    Err("Timeout waiting for message handling to complete".to_string())
                }
            };

            // Disconnect
            println!("🔌 Disconnecting...");
            client
                .disconnect()
                .await
                .map_err(|e| format!("Failed to disconnect: {}", e))?;
            println!("👋 Disconnected from iFlow");

            message_result.map_err(|e| format!("WebSocket client error: {}", e))
        })
        .await
        .map_err(|e| format!("WebSocket client error: {}", e))?;

    // Extract the summary from the holder and return it
    let summary = summary_holder.lock().map(|g| g.clone()).unwrap_or(None);
    Ok(summary)
}
